#include <stdio.h>
#include <windows.h>
#include <assert.h>
#include <stdlib.h>
#include <math.h>

//Global variable
HANDLE m_hCommPort;
DWORD WINAPI ComThreadFunc();
int gap = 20;
int num = 1000;
int com_tx(HANDLE hComm,unsigned char *txbuf, unsigned char txlen);
int task = 0;

void main(int argc,char *argv[])
{	
	DCB dcb;
	char input;
	int res = 0;
	char  ComPortName[16];
	
	if(argc < 5) 
    {
        res = -1;
        goto arg_err;
	}
	for(res = 0; res<argc ; res++)
      printf("%s ",argv[res]);
    printf("\n");
      if(strcmp(argv[1],"-s") == 0)
      {
        sprintf(ComPortName,"COM%d",atoi(argv[2]));
      }
      else
      {
        res = -1;
      }
      
	  if(strcmp(argv[3],"-t") == 0)
      {
        gap = atoi(argv[4]);
		gap= gap<5?5:gap;
      }
      else
      {
        res = -1;
      }
	  
	  if(argc == 7 && strcmp(argv[5],"-n") == 0)
      {
        num = atoi(argv[6]);
		num= num<1000?1000:num;
      }

	  
      arg_err:
      if(res == -1)
      {
        printf("\narguments input error,%s -s 8 -t 50",argv[0]);
        printf("\nexit!\n");
        //_getch();
        return;
      }
	  

	
		/*Open a file! Here is comm!*/
		m_hCommPort= CreateFile(ComPortName,
			GENERIC_READ|GENERIC_WRITE, 
			0,
			NULL,
			OPEN_EXISTING,
			FILE_FLAG_OVERLAPPED,
			0);
		
		if(INVALID_HANDLE_VALUE==m_hCommPort)
		{
			printf("invalid handle!\n");
			return;
		}
		/*Set comm state!*/
		
		if(!SetupComm(m_hCommPort,1024,1024))	// set the inqueue&outqueue buffer
		{
			printf("Setup Comm input buffer and output buffer failed!\n");
		}
		
		if (!GetCommState(m_hCommPort,&dcb)) {
			// Handle the error.
			printf ("GetCommState failed with error %d.\n", GetLastError());
			return;
		}
		
		
		
		dcb.BaudRate = CBR_9600;     // set the baud rate
		dcb.ByteSize = 8;             // data size, xmit, and rcv
		dcb.Parity = NOPARITY;        // no parity bit
		dcb.StopBits = ONESTOPBIT;    // one stop bit		
		
		if (!SetCommState(m_hCommPort, &dcb)) {
			// Handle the error.
			printf ("SetCommState failed with error %d.\n", GetLastError());
			return;
		}
		
		
		printf("set com%s with baudrate 9600 seccussfully!\n", argv[2]);

/*------------------------------------ Setting Timeouts --------------------------------------------------*/
			
			COMMTIMEOUTS timeouts = { 50 };
			timeouts.ReadIntervalTimeout         = 5;
			timeouts.ReadTotalTimeoutConstant    = 150;
			timeouts.ReadTotalTimeoutMultiplier  = 5;
			timeouts.WriteTotalTimeoutConstant   = 50;
			timeouts.WriteTotalTimeoutMultiplier = 5;
			
			if (SetCommTimeouts(m_hCommPort, &timeouts) == FALSE)
				printf("\n\n    Error! in Setting Time Outs");
			else
				printf("\n\n    Setting Serial Port Timeouts Successfull");
			
		/*Set comm mask*/
		if(!SetCommMask(m_hCommPort,EV_RXCHAR|EV_RXFLAG))
		{
			printf("Set comm mask failed!");
		}

		/*Create thread!*/
		HANDLE hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ComThreadFunc,NULL,0,NULL);
		task = 1;
		CloseHandle(hThread);
		
		while(1)
		{
			//main thread
			getchar();
			if(task == 0)
				return;
		}
	
}
 
DWORD WINAPI ComThreadFunc()
{
	char buff[1024]={0};
	DWORD res,factbyte;
	COMSTAT rst;
	int fError,commEvError;
	int tx_cnt = 0;
	int rx_cnt = 0;
	DWORD dwEvtMask,CommResult,readResult;
	BOOL bRet;
	BOOL fWaitingOnStat=FALSE;	// indicate if wait comm event is pending.
	OVERLAPPED osComm = {0};	// overlapped structure for comm event operations
	OVERLAPPED osReader = {0};  // overlapped structure for read operations
	OVERLAPPED osWrite = {0};
	
	printf("I am the comm thread!\n");
	
	
	osComm.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	if (osComm.hEvent == NULL)
		printf("Create comm Event failed!\n");
	osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	if (osReader.hEvent == NULL)
		printf("Create reader Event failed!\n");
	
	
	
	sprintf(buff,"hello world!\n");
	
	unsigned int rec_bytes = 0;
	int i;
	while(1)
	{
		for(i=0;i<5;i++)
		{
			WriteFile(m_hCommPort,               // Handle to the Serialport
						   "\xFF\x01\x00\x4d\x00\x00\x5e",            // Data to be written to the port 
						   7,   // No of bytes to write into the port
						   &factbyte,  // No of bytes written to the port
						   &osWrite);
			Sleep(10);
		}
		WriteFile(m_hCommPort,               // Handle to the Serialport
						   "\xFF\x01\x00\x53\x00\x00\x54",            // Data to be written to the port 
						   7,   // No of bytes to write into the port
						   &factbyte,  // No of bytes written to the port
						   &osWrite);
        Sleep(10);
		if(!fWaitingOnStat)
		{
			bRet=WaitCommEvent(m_hCommPort,&dwEvtMask,&osComm);
			if(!bRet)
			{
				commEvError=GetLastError();
				assert(commEvError==ERROR_IO_PENDING);
				fWaitingOnStat=TRUE;
				//printf("WaitCommEvent !bRet\n");
			}
			else
			{
				//WaitCommEvent always will return FALSE for overlapped I/O
				//printf("WaitCommEvent always will return FALSE for overlapped I/O");
			}
		}
		/*wait for pending operations to complete*/
		if(fWaitingOnStat)
		{
			CommResult=WaitForSingleObject(osComm.hEvent,gap>20?gap-10:10);//Now it can't get the event???Block for ever!!
			
			switch(CommResult)
			{
			case WAIT_OBJECT_0:
				ClearCommError(m_hCommPort,&res,&rst);
				if(!ReadFile(m_hCommPort,buff,rst.cbInQue,&factbyte,&osReader))
				{
					fError=GetLastError();
					assert(fError==ERROR_IO_PENDING);
					readResult=WaitForSingleObject(osReader.hEvent,0);
					switch(readResult)
					{
					case WAIT_OBJECT_0:
						//printf("\n\nfactbyte:%d\n",factbyte);
						printf("rec ok\n");
						rx_cnt ++;
						rec_bytes += factbyte;
						memset(buff,0,1024);
						fWaitingOnStat=FALSE;
					case WAIT_TIMEOUT:
						//ClearCommError(m_hCommPort,&res,&rst);
						//SetCommMask(m_hCommPort,EV_RXCHAR|EV_RXFLAG);
						break;
					default:
						//do nothing!
						break;
					}
				}
				else
				{
					buff[rst.cbInQue]=0;
					//printf("%s",buff);
					printf("rec ok\n");
					memset(buff,0,1024);
					rx_cnt ++;
					rec_bytes += factbyte;
					fWaitingOnStat=FALSE;
				}
				break;
			case WAIT_TIMEOUT:
				printf("wait %dms timeout!\n",gap);
				//ClearCommError(m_hCommPort,&res,&rst);
				//SetCommMask(m_hCommPort,EV_RXCHAR|EV_RXFLAG);
				break;
			default:
				//do nothing!
				break;
			}
		}
		printf("tx:%d\n",tx_cnt++);
		if(tx_cnt >=num)
		{
			printf("tx pack %d\nrx pack %d\ntotal\nsucces %.3f%%",tx_cnt,rx_cnt,(float)rx_cnt/num*100);
			task = 0;
			Sleep(10);
			return 1;
		}
	}
	return 0L;
}
